package cn.itcast.nems.approval.service;

import cn.hutool.core.collection.CollectionUtil;
import cn.itcast.ic.common.bean.Page;
import cn.itcast.nems.approval.dao.entity.ApprovalForm;
import cn.itcast.nems.approval.enumeration.ApprovalFormStateEnum;
import cn.itcast.nems.common.PageQueryModel;
import cn.itcast.nems.studentrecord.dao.dataobject.ApprovalFormQueryModel;
import com.baomidou.mybatisplus.extension.service.IService;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public interface ApprovalFormService extends IService<ApprovalForm> {


    /**
     * <p>
     * 查询待办审批单
     * </p>
     *
     * @param queryModel 查询条件
     * @return 审批单列表 （ID）
     * @author zhouwei
     * @since 2024/1/16 6:00 PM
     **/
    List<ApprovalForm> getWaitApprovalFormList(ApprovalFormQueryModel queryModel);

    /**
     * 功能描述：发起审批 <p/> 注：调用该审批方法前应先处理单据的业务逻辑 或 保证业务逻辑和审批逻辑的原子性
     *
     * @param journalType   凭单类型
     * @param journalId     凭单ID
     * @param variables     审批流程上要求的条件变量
     * @param passbackParam BPM透明回传的参数，可以记录特殊处理逻辑的变量
     * @return 审批流程单ID
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月21日
     */
    public String start(final JournalType journalType, final String journalId, final Map<String, Object> variables, String passbackParam);

    /**
     * 功能描述：撤回审批 <p/> 注：调用该审批方法前应先处理单据的业务逻辑 或 保证业务逻辑和审批逻辑的原子性；审批流程的最终通过依赖于BPM的事件处理。
     *
     * @param formID 审批流程单ID，等同于BusinessKey
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月21日
     */
    public void cancel(final String formID);

    /**
     * 退回发起人
     * @param formID
     */
    public void rollbackRequester(final String formID);

    /**
     * 退回上一级
     * @param formID
     */
    public void rollbackPrevious(final String formID);

    /**
     * 功能描述：单个节点的审批 <p/> 注：调用该审批方法前应先处理单据的业务逻辑 或 保证业务逻辑和审批逻辑的原子性
     *
     * @param formID             审批流程单ID
     * @param result             审批结果：通过 或 不通过
     * @param comment            审批备注
     * @param additionalFormJson 审批时填写的补充表单；JSON格式：{"nodeKey":"", form:{"fieldKey":"","fieldKey":"","fieldValue":""}}
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月21日
     */
    public void approve(final String formID, final ApproveResult result, final String comment, final String additionalFormJson, Integer applyType);

    public void approve(final String formID, final ApproveResult result, final String comment, final String additionalFormJson, Integer applyType, Map<String, Object> variables);

    /**
     * 功能描述：催办审批流程 <p/> 注：调用该审批方法前应先处理单据的业务逻辑 或 保证业务逻辑和审批逻辑的原子性
     *
     * @param formID         审批流程单ID
     * @param targetAssignee 指定要催办的人，该催办人必须为当前审批节点的审批成员。为空时默认催办节点的所有审批成员
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月21日
     */
    String remind(final String formID, final String targetAssignee);

    /**
     * 功能描述：审批流程结束（全部审批通过）
     *
     * @param formID 审批流程单ID
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月22日
     */
    public void finish(final String formID);

    /**
     * 功能描述：审批流最终处理失败
     *
     * @param formID  表单
     * @param message 异常消息
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2024年3月14日
     */
    public void fail(final String formID, final String message);

    /**
     * 功能描述：通过bpmBusinesskey获取审批单信息
     *
     * @param bpmBusinesskey 流程审批发起时传的BusinessKey，通常为ApprovalFormID
     * @return 审批单
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月22日
     */
    public ApprovalForm getByBusinessKey(String bpmBusinesskey);

    /**
     * 功能描述：根据凭单查询当前正在进行中的审批单
     *
     * @param journalType 凭单类型
     * @param journalId   凭单ID
     * @return 正在进行中的流程审批单
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年11月23日
     */
    List<ApprovalForm> getActiveByJournalId(JournalType journalType, String journalId, List<ApprovalFormStateEnum> stateList);

    List<String> getFormIDs(String formID);

    /**
     * 功能描述：获取待我审批的审批单列表
     *
     * @param page        TODO
     * @param journalType 单据类型
     * @return 待我审批单列表
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年12月3日
     */
    Page<ApprovalForm> listMyTodo(PageQueryModel<?> page, JournalType journalType);

    /**
     * 功能描述：获取待我审批的审批单数量
     *
     * @param journalType 单据类型
     * @return 待我审批单数量
     * @author 刘曙
     * @update:[变更日期YYYY-MM-DD][更改人姓名][变更描述]
     * @since 2023年12月3日
     */
    Integer getMyTodoCount(JournalType journalType);

    /**
     * 根据账户邮箱获取审批过的表单
     *
     * @param accountEmail 账户邮箱
     * @param journalType  凭单类型
     * @return java.util.List<cn.itcast.nems.approval.dao.entity.ApprovalForm>
     * @author 高昌露
     * @since 2023/11/29 14:18
     */
    List<ApprovalForm> getMyApprovedForms(@NonNull JournalType journalType, @NonNull String accountEmail);

    /**
     * 功能描述: 获取待我审批ids（需要我审批的 ： 带我审批的）
     * 用法：List<String> ids = approvalFormService.listWaitApprovalIds(ApprovalFormService.JournalType.JOURNAL_DROPOUT);
     *
     * @return journalType 凭单类型
     * @author 陈早庆
     * @update:[变更日期2023年12月07日][更改人姓名][变更描述]
     * @since 2023年12月07日
     */
    List<String> listWaitApprovalIds(JournalType journalType);

    List<String> getJournalIdFormIds(JournalType journalType);

    /**
     * 修改流程审批单描述信息
     *
     * @param formId  流程审批单ID
     * @param message 描述消息
     * @author 李勇
     * @since 2024年04月02日
     */
    void updateDescription(final String formId, final String message);

    /**
     * 获取待我审批 + 我审批过的凭单ID
     *
     * @param journalType  凭单类型
     * @param accountEmail 账户邮箱
     * @return java.util.List<java.lang.String>
     * @author 高昌露
     * @since 2023/12/13 16:04
     */
    default List<String> getMyApprovedAndWaitApprovalIds(@NonNull JournalType journalType, @NonNull String accountEmail) {
        List<String> result = new ArrayList<>();
        // 审批过的
        List<ApprovalForm> myApprovedForms = this.getMyApprovedForms(journalType, accountEmail);
        if (CollectionUtil.isNotEmpty(myApprovedForms)) {
            result.addAll(myApprovedForms.stream().map(ApprovalForm::getJournalId).toList());
        }
        // 待我审批
        List<String> waitApprovalIds = this.listWaitApprovalIds(journalType);
        if (CollectionUtil.isNotEmpty(waitApprovalIds)) {
            result.addAll(waitApprovalIds);
        }
        return result;
    }


    /**
     * 审批结果
     *
     * @author 刘曙
     * @since 2023年11月21日
     */
    public enum ApproveResult {
        /**
         * 审批通过
         */
        APPROVE,
        /**
         * 审批未通过
         */
        REJECT;
    }

    /**
     * 凭单类型
     *
     * @author 刘曙
     * @since 2023年11月21日
     */
    @Getter
    @AllArgsConstructor
    public enum JournalType {
        RENEWAL("升级凭单"),
        EXCHANGE("转班凭单"),
        TRANSFER("转移凭单"),
        SUSPENSION("休学凭单"),
        DROPOUT("退学凭单"),
        DELAY("转待定班凭单"),
        FINAL("结课凭单"),
        RECEIVABLE_ADJUSTMENT("调价单"),
        DISCOUNT("优惠单"),
        REPEAT("重读凭单"),
        FUND_TRANSFER("费用转移凭单"),
        REFUND("退费凭单"),
        DROPOUT_REFUND("退学退费凭单"),
        ;

        final String cnName;
    }
}
